home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / KERNEL.C < prev    next >
C/C++ Source or Header  |  1997-09-14  |  19KB  |  781 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  
  5. #undef    PROCTRACE        /* kernel debugging */
  6.  
  7. #include "global.h"
  8. #include "commands.h"
  9. #ifdef SETPSINFO
  10. #include "timer.h"
  11. #endif
  12. #include "mbuf.h"
  13. #include "proc.h"
  14. #include "socket.h"
  15. #include "daemon.h"
  16. #include "hardware.h"
  17. #ifdef SOUNDS
  18. #include <sys/wait.h>
  19. #endif
  20.  
  21. #if !defined(_lint)
  22. static char rcsid[] OPTIONAL = "$Id: kernel.c,v 1.24 1997/09/14 14:37:46 root Exp root $";
  23. #endif
  24.  
  25. struct proc *Curproc;        /* Currently running process */
  26. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  27. struct proc *Waittab[PHASH];    /* Waiting process list */
  28. struct proc *Susptab;        /* Suspended processes */
  29. static struct proc *Rdytail;
  30. static struct proc *Waittail[PHASH];
  31. static struct proc *Susptail;
  32. static struct mbuf *Killq;
  33.  
  34. #ifdef SETPSINFO
  35. extern char shortversion[];
  36. #endif
  37.  
  38.  
  39. extern void stopalltimers (struct proc *pp);
  40. extern void tnosfcloseall (struct proc *p);
  41. int valid_proc (struct proc *pp);
  42. static void addproc (struct proc * entry);
  43. static void delproc (struct proc * entry);
  44. static int procsigs (void);
  45. static void ksig (volatile void *event, int n);
  46. struct ksig Ksig;
  47. void volatile *lastkernelevent = (void *)0;
  48.  
  49. /* Create a process descriptor for the main function. Must be actually
  50.  * called from the main function!
  51.  * Note that standard I/O is NOT set up here.
  52.  */
  53. struct proc *
  54. mainproc (const char *name)
  55. {
  56. register struct proc *pp;
  57.  
  58.     /* Create process descriptor */
  59.     pp = (struct proc *) callocw (1, sizeof (struct proc));
  60.  
  61.     /* Create name */
  62.     pp->name = strdup (name);
  63.  
  64.     /* Initialize the magic numbers */
  65.     pp->magic1 = PROC_MAGIC1;
  66.     pp->magic2 = PROC_MAGIC2;
  67.  
  68. #ifdef UNIX
  69.     pp->stksize = STACKBASE;
  70.     pp->stack = (void *) STACKBASE;
  71. #else    /* UNIX */
  72.  
  73. #ifdef TNOS_68K
  74.     pp->stksize = _stklen / sizeof (int16);
  75. #endif
  76. #ifdef MSDOS
  77.     pp->stksize = 0;
  78. #endif
  79.     pp->stack = 0;
  80.  
  81. #endif    /* UNIX */
  82.     /* Make current */
  83.     pp->state = READY;
  84.     Curproc = pp;
  85.     return pp;
  86. }
  87.  
  88.  
  89.  
  90. /* Create a new, ready process and return pointer to descriptor.
  91.  * The general registers are not initialized, but optional args are pushed
  92.  * on the stack so they can be seen by a C function.
  93.  */
  94. struct proc *
  95. newproc (
  96. const char *name,            /* Arbitrary user-assigned name string */
  97. unsigned int stksize,            /* Stack size in words to allocate */
  98. void (*pc) (int, void *, void *),    /* Initial execution address */
  99. int iarg,                /* Integer argument (argc) */
  100. void *parg1,                /* Generic pointer argument #1 (argv) */
  101. void *parg2,                /* Generic pointer argument #2 (session ptr) */
  102. int freeargs                /* If set, free arg list on parg1 at termination */
  103. ) {
  104. register struct proc *pp;
  105. int i;
  106.  
  107.     /* Create process descriptor */
  108.     pp = (struct proc *) callocw (1, sizeof (struct proc));
  109.  
  110.     /* Create name */
  111.     pp->name = strdup (name);
  112.  
  113.     /* Initialize the magic numbers */
  114.     pp->magic1 = PROC_MAGIC1;
  115.     pp->magic2 = PROC_MAGIC2;
  116.  
  117.     /* Allocate stack */
  118.     if (stksize) {
  119.         stksize *= 2;
  120.         stksize = (stksize < 1024) ? 1024 : stksize;
  121.     }
  122.     stksize += 3072;
  123.  
  124.     stksize = (stksize + 3) & ~3;
  125.     pp->stksize = stksize;
  126.     if ((pp->stack = (int16 *) mallocw (sizeof (int16) * pp->stksize)) == NULL) {
  127.         free (pp->name);
  128.         free ((char *) pp);
  129.         return NULLPROC;
  130.     }
  131.     /* Initialize stack for high-water check */
  132.     for (i = 0; (unsigned) i < stksize; i++)
  133.         pp->stack[i] = STACKPAT;
  134.  
  135.     pp->func = pc;
  136.     pp->freeargs = freeargs;
  137.     pp->iarg = iarg;
  138.     pp->parg1 = parg1;
  139.     pp->parg2 = parg2;
  140.  
  141.     /* Task initially runs with interrupts on */
  142.     pp->i_state = 1;
  143.  
  144.     /* Do machine-dependent initialization of stack */
  145.     psetup (pp);
  146.  
  147.  
  148.     /* Inherit creator's input and output sockets */
  149.     (void) usesock (Curproc->input);
  150.     pp->input = Curproc->input;
  151.     (void) usesock (Curproc->output);
  152.     pp->output = Curproc->output;
  153.  
  154. #ifdef UNIX
  155.     /*
  156.      * The old "curses" tty driver faked this, occasionally getting it
  157.      * not quire right (IMHO, but the DOS version did the same implicitly).
  158.      * The new one uses this pointer to get it "right".
  159.      *
  160.      * The session manager uses this because multiple sessions (potentially
  161.      * all of them!) can be simultaneously "current" (e.g. "xterm" session
  162.      * manager).  This is even more important with external sessions, which
  163.      * are *always* "current".
  164.      */
  165.     pp->session = Curproc->session;
  166. #endif
  167.  
  168.     /* Add to ready process table */
  169.     pp->state = READY;
  170.     addproc (pp);
  171.     return pp;
  172. }
  173.  
  174.  
  175.  
  176. /* Free resources allocated to specified process. If a process wants to kill
  177.  * itself, the reaper is called to do the dirty work. This avoids some
  178.  * messy situations that would otherwise occur, like freeing your own stack.
  179.  */
  180. void
  181. killproc (register struct proc *pp)
  182. {
  183. char **argv;
  184.  
  185.     if (!valid_proc (pp))
  186.         return;
  187.  
  188.     /* Don't check the stack here! Will cause infinite recursion if
  189.      * called from a stack error
  190.      */
  191.  
  192.     if (pp == Curproc)
  193.         killself ();    /* Doesn't return */
  194.  
  195.     /* Stop alarm clock in case it's running (also done in killself() */
  196.     stop_timer (&pp->alarm);
  197.     stopalltimers (pp);
  198.  
  199.     /* Close any open sockets and files */
  200.     freesock (pp);
  201.     tnosfcloseall (pp);
  202.  
  203.     close_s (pp->input);
  204.     close_s (pp->output);
  205.  
  206.     /* Alert everyone waiting for this proc to die */
  207.     ksignal (pp, 0);
  208.  
  209.     /* Remove from appropriate table */
  210.     delproc (pp);
  211.  
  212.     /* Free allocated memory resources */
  213.     if (pp->freeargs == 1) {
  214.         argv = pp->parg1;
  215.         while (pp->iarg-- != 0)
  216.             free (*argv++);
  217.         free (pp->parg1);
  218.     }
  219.  
  220.     if (pp->freeargs == 2)
  221.         free (pp->parg2);
  222.     free (pp->name);
  223.     free (pp->stack);
  224.     free (pp->outbuf);
  225.     free ((char *) pp);
  226. }
  227.  
  228.  
  229.  
  230. /* Terminate current process by sending a request to the killer process.
  231.  * Automatically called when a process function returns. Does not return.
  232.  */
  233. void
  234. killself ()
  235. {
  236. register struct mbuf *bp;
  237. char *cp;
  238.  
  239.     if (Curproc != NULLPROC) {
  240. #if 0
  241.         /* Stop alarm clock in case it's running (also done in killproc() */
  242.         stop_timer (&Curproc->alarm);
  243.         stopalltimers (Curproc);
  244. #endif
  245.         bp = pushdown (NULLBUF, sizeof (Curproc));
  246.         memcpy (bp->data, (char *) &Curproc, sizeof (Curproc));
  247.         enqueue (&Killq, bp);
  248.     }
  249.  
  250.     cp = (char *) mallocw (strlen (Curproc->name) + 1 + strlen (" (zombie)"));
  251.     if (cp)    {
  252.         sprintf (cp, "%s (zombie)", Curproc->name);
  253.         chname (Curproc, cp);
  254.         free (cp);
  255.     }
  256.  
  257.     /* "Wait for me; I will be merciful and quick." */
  258.     for (;;)
  259.         kwait (NULL);
  260. }
  261.  
  262.  
  263.  
  264. /* Process used by processes that want to kill themselves */
  265. void
  266. killer (int i OPTIONAL, void *v1 OPTIONAL, void *v2 OPTIONAL)
  267. {
  268. struct proc *pp;
  269. struct mbuf *bp;
  270.  
  271.     server_disconnect_io ();
  272.     for ( ; ; ) {
  273.         while ((volatile struct mbuf *) Killq == NULLBUF)
  274.             kwait (&Killq);
  275.         bp = dequeue (&Killq);
  276.         (void) pullup (&bp, (unsigned char *) &pp, sizeof (pp));
  277.         free_p (bp);
  278.         if (pp != Curproc)    /* We're immortal */
  279.             killproc (pp);
  280.     }
  281. }
  282.  
  283.  
  284.  
  285. /* Inhibit a process from running */
  286. void
  287. suspend (struct proc *pp)
  288. {
  289.     if (!valid_proc (pp))
  290.         return;
  291.  
  292.     if (pp != Curproc)
  293.         delproc (pp);    /* Running process isn't on any list */
  294.     pp->state |= SUSPEND;
  295.     if (pp != Curproc)
  296.         addproc (pp);    /* kwait will do it for us */
  297.     else
  298.         kwait (NULL);
  299. }
  300.  
  301.  
  302.  
  303. /* Restart suspended process */
  304. void
  305. resume (struct proc *pp)
  306. {
  307.     if (!valid_proc (pp))
  308.         return;
  309.  
  310.     if (pp != Curproc)
  311.         delproc (pp);        /* Can't be Curproc! */
  312.     pp->state &= ~SUSPEND;
  313.     if (pp != Curproc)
  314.         addproc (pp);    /* kwait will do it for us */
  315.     else
  316.         kwait (NULL);
  317. }
  318.  
  319.  
  320.  
  321. /* Wakeup waiting process, regardless of event it's waiting for. The process
  322.  * will see a return value of "val" from its kwait() call.
  323.  */
  324. void
  325. alert (struct proc *pp, int val)
  326. {
  327.     if (!valid_proc (pp))
  328.         return;
  329.  
  330. #ifdef    PROCTRACE
  331.     tcmdprintf ("alert(%lx,%u) [%s]\n", ptol (pp), val, pp->name);
  332. #endif
  333.     if (pp != Curproc)
  334.         delproc (pp);
  335.     pp->state &= ~WAITING;
  336.     pp->retval = val;
  337.     pp->event = 0;
  338.     if (pp != Curproc)
  339.         addproc (pp);
  340.     else
  341.         kwait (NULL);
  342. }
  343.  
  344.  
  345.  
  346. /* Post a wait on a specified event and give up the CPU until it happens. The
  347.  * null event is special: it means "I don't want to block on an event, but let
  348.  * somebody else run for a while". It can also mean that the present process
  349.  * is terminating; in this case the wait never returns.
  350.  *
  351.  * Kwait() returns 0 if the event was signaled; otherwise it returns the
  352.  * arg in an alert() call. Kwait must not be called from interrupt level.
  353.  *
  354.  * Before waiting and after giving up the CPU, kwait() processes the signal
  355.  * queue containing events signaled when interrupts were off. This means
  356.  * the process queues are no longer modified by interrupt handlers,
  357.  * so it is no longer necessary to run with interrupts disabled here. This
  358.  * greatly improves interrupt latencies.
  359.  */
  360. int
  361. kwait (volatile void *event)
  362. {
  363. struct proc *oldprocptr;
  364. int tmp;
  365. int i_state;
  366.  
  367.     Ksig.kwaits++;
  368.  
  369.     /* Enable interrupts, after saving the current state.
  370.      * This minimizes interrupt latency since we may have a lot
  371.      * of work to do. This seems safe, since care has been taken
  372.      * here to ensure that signals from interrupt level are not lost, e.g.,
  373.      * if we're waiting on an event, we post it before we scan the
  374.      * signal queue.
  375.      */
  376.     i_state = istate();
  377.     if (!i_state)
  378.         Ksig.kwaitints++;
  379.     (void) enable ();
  380.     
  381.     if(event != NULL){
  382.         /* Post a wait for the specified event */
  383.         Curproc->event = event;
  384.         Curproc->state = WAITING;
  385.         addproc(Curproc);    /* Put us on the wait list */
  386.     }
  387.     /* If the signal queue contains a signal for the event that we're
  388.      * waiting for, this will wake us back up
  389.      */
  390.     (void) procsigs();
  391.     if (event == NULL){
  392.         /* We remain runnable */
  393.         if (Rdytab == NULL) {
  394.             /* Nothing else is ready, so just return */
  395.             Ksig.kwaitnops++;
  396.             restore(i_state);
  397.             return 0;
  398.         }
  399.         addproc(Curproc); /* Put us on the end of the ready list */
  400.     }
  401.     /* Look for a ready process and run it. If there are none,
  402.      * loop or halt until an interrupt makes something ready.
  403.      */
  404.     while(Rdytab == NULL){
  405.         /* Give system back to upper-level multitasker, if any.
  406.          * Note that this function enables interrupts internally
  407.          * to prevent deadlock, but it restores our state
  408.          * before returning.
  409.          */
  410.         giveup();
  411.         /* Process signals that occurred during the giveup() */
  412.         (void) procsigs();
  413.     }
  414.     /* Remove first entry from ready list */
  415.     oldprocptr = Curproc;
  416.     Curproc = Rdytab;
  417.     delproc(Curproc);
  418.  
  419.     /* Now do the context switch.
  420.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  421.      *
  422.      * First save the current process's state. Then if
  423.      * this is still the old process, load the new environment. Since the
  424.      * new task will "think" it's returning from the setjmp() with a return
  425.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  426.      * would otherwise cause an infinite loop.
  427.      */
  428. #ifdef    PROCTRACE
  429.     if (strcmp (oldprocptr->name, Curproc->name) != 0)
  430.         tcmdprintf ("kwait -> %s(%d)\n", Curproc->name, !!Curproc->i_state);
  431. #endif
  432.     /* Save old state */
  433.     if (oldprocptr)    {
  434.         oldprocptr->i_state = 0;
  435.         if(i_state)
  436.             oldprocptr->i_state = 1;
  437.     }
  438.     if(!oldprocptr || setjmp(oldprocptr->env) == 0){
  439.         /* We're still running in the old task; load new task context.
  440.          * The interrupt state is restored here in case longjmp
  441.          * doesn't do it (e.g., systems other than Turbo-C).
  442.          */
  443.         restore(Curproc->i_state);
  444.         longjmp(Curproc->env,1);
  445.     }
  446.     /* At this point, we're running in the newly dispatched task */
  447.     tmp = Curproc->retval;
  448.     Curproc->retval = 0;
  449.  
  450.     /* Also restore the true interrupt state here, in case the longjmp
  451.      * DOES restore the interrupt state saved at the time of the setjmp().
  452.      * This is the case with Turbo-C's setjmp/longjmp.
  453.      */
  454.     restore(Curproc->i_state);
  455.  
  456. #if 0
  457.     /* If an exception signal was sent and we're prepared, take it */
  458.     if((Curproc->flags.sset) && tmp == Curproc->signo)
  459.         longjmp(Curproc->sig,1);
  460. #endif
  461.  
  462.     /* Otherwise return normally to the new task */
  463.     return tmp;
  464. }
  465.  
  466.  
  467.  
  468. int
  469. ksignal (volatile void *event, int n)
  470. {
  471. int cnt;
  472.  
  473.     if(istate())    {
  474.         /* Interrupts are on, just call ksig directly after
  475.          * processing the previously queued signals
  476.          */
  477.         cnt = procsigs ();
  478.         ksig (event, n);
  479.         return cnt;
  480.     }
  481.  
  482.     /* Interrupts are off, so quickly queue event */
  483.     Ksig.ksigsqueued++;
  484.  
  485.      /* Ignore duplicate signals to protect against a mad device driver
  486.      * overflowing the signal queue
  487.      */
  488.     if(event == lastkernelevent && Ksig.nentries != 0){
  489.         Ksig.duksigs++;
  490.         return 0;
  491.     }
  492.     
  493.     if(Ksig.nentries == SIGQSIZE){
  494.         /* It's hard to handle this gracefully */
  495.         Ksig.lostsigs++;
  496.         return 0;
  497.     }
  498.     
  499.     lastkernelevent = Ksig.wp->event = event;
  500.     Ksig.wp->n = n;
  501.     if (++Ksig.wp > &Ksig.entry[SIGQSIZE - 1])
  502.         Ksig.wp = Ksig.entry;
  503.     Ksig.nentries++;
  504.     return 0;
  505. }
  506.  
  507.  
  508.  
  509. static int
  510. procsigs(void)
  511. {
  512. int cnt = 0;
  513. int tmp;
  514. int i_state;
  515. #ifndef MSDOS
  516. static time_t nextsecond = 0;
  517. time_t thissecond;
  518. #endif
  519.  
  520.     for ( ; ; )    {
  521.         /* Atomic read and decrement of entry count */
  522.         i_state = disable ();
  523.         tmp = Ksig.nentries;
  524.         if (tmp != 0)
  525.             Ksig.nentries--;
  526.         restore(i_state);
  527.         
  528.         if (tmp == 0)
  529.             break;
  530.         ksig (Ksig.rp->event, Ksig.rp->n);
  531.         if (++Ksig.rp > &Ksig.entry[SIGQSIZE - 1])
  532.             Ksig.rp = Ksig.entry;
  533.         cnt++;
  534.     }
  535.     
  536.     if (cnt > Ksig.maxentries)
  537.         Ksig.maxentries = cnt;    /* Record high water mark */
  538.  
  539. #ifndef MSDOS
  540.     /* While this may NOT be the best place for these, this routine
  541.        will NOT accidentally get killed or be omitted to be compiled
  542.        in, so it makes the best place (for the time being). */
  543.     thissecond = time ((time_t *)0);
  544.     if (nextsecond < thissecond)    {
  545. #ifdef SOUNDS
  546.         /* this is to clean up zombie processes from playing sounds */
  547.         (void) waitpid (0, NULL, WNOHANG);
  548. #endif
  549. #ifdef SETPSINFO
  550.         {
  551.             char buf[64];
  552.  
  553.             sprintf (buf, "%s (%sRegistered) - UP: %s", shortversion, (is_registered ())? "" : "Not ", tformat (secclock ()));
  554.             setprocname (buf);
  555.         }
  556. #endif
  557.         nextsecond = thissecond + 5;
  558.     }
  559. #endif
  560.     return cnt;
  561. }
  562.  
  563.  
  564.  
  565. /* Make ready the first 'n' processes waiting for a given event. The ready
  566.  * processes will see a return value of 0 from kwait().  Note that they don't
  567.  * actually get control until we explicitly give up the CPU ourselves through
  568.  * a kwait(). ksig is now called from pwait, which is never called at
  569.  * interrupt time, so it is no longer necessary to protect the proc queues
  570.  * against interrupts. This also helps interrupt latencies considerably.
  571.  */
  572. static void
  573. ksig(
  574. volatile void *event,    /* Event to signal */
  575. int n        /* Max number of processes to wake up */
  576. ){
  577. struct proc *pp;
  578. struct proc *pnext;
  579. unsigned int hashval;
  580. int cnt = 0;
  581.  
  582.     Ksig.ksigs++;
  583.  
  584.     if(event == NULL){
  585.         Ksig.ksignops++;
  586.         return;        /* Null events are invalid */
  587.     }
  588.  
  589.     /* n == 0 means "signal everybody waiting for this event" */
  590.     if(n == 0)
  591.         n = 65535;
  592.  
  593.     hashval = phash(event);
  594.     for (pp = Waittab[hashval]; n != 0 && pp != NULLPROC; pp = pnext)    {
  595.         pnext = pp->next;
  596.         if(pp->event == event){
  597. #ifdef    PROCTRACE
  598.             tcmdprintf ("ksignal(%lx,%u) wake waiting %lx [%s]\n", ptol (event), n,
  599.                  ptol (pp), pp->name);
  600. #endif
  601.             delproc (pp);
  602.             pp->state &= ~WAITING;
  603.             pp->retval = 0;
  604.             pp->event = NULL;
  605.             addproc (pp);
  606.             n--;
  607.             cnt++;
  608.         }
  609.     }
  610.     for (pp = Susptab; n != 0 && pp != NULLPROC; pp = pnext)    {
  611.         pnext = pp->next;
  612.         if(pp->event == event){
  613. #ifdef    PROCTRACE
  614.             tcmdprintf ("ksignal(%lx,%u) wake suspended %lx [%s]\n", ptol (event), n,
  615.                  ptol (pp), pp->name);
  616. #endif /* PROCTRACE */
  617.             delproc (pp);
  618.             pp->state &= ~WAITING;
  619.             pp->event = 0;
  620.             pp->retval = 0;
  621.             addproc (pp);
  622.             n--;
  623.             cnt++;
  624.         }
  625.     }
  626.     if(cnt == 0)
  627.         Ksig.ksignops++;
  628.     else
  629.         Ksig.ksigwakes += (unsigned long) cnt;
  630. }
  631.  
  632.  
  633.  
  634. /* Rename a process */
  635. void
  636. chname (struct proc *pp, const char *newname)
  637. {
  638.     free (pp->name);
  639.     pp->name = strdup (newname);
  640. }
  641.  
  642.  
  643.  
  644. int
  645. valid_proc (struct proc *pp)
  646. {
  647.     if (pp == NULLPROC)
  648.         return 0;
  649.     if (pp->magic1 != PROC_MAGIC1 || pp->magic2 != PROC_MAGIC2)
  650.         return 0;
  651.     if (pp->state > (SUSPEND + 1))
  652.         return 0;
  653.     return 1;
  654. }
  655.  
  656.  
  657.  
  658. /* Remove a process entry from the appropriate table */
  659. static void
  660. delproc (entry)
  661. register struct proc *entry;    /* Pointer to entry */
  662. {
  663. int i_state;
  664. struct proc *next = NULLPROC;
  665. struct proc *prev = NULLPROC;
  666.  
  667.     if (!valid_proc (entry))
  668.         return;
  669.  
  670.     i_state = disable ();
  671.  
  672.     if (valid_proc (entry->prev))
  673.         prev = entry->prev;
  674.  
  675.     if (valid_proc (entry->next))    {
  676.         entry->next->prev = prev;
  677.         next = entry->next;
  678.     }
  679.  
  680.     if (prev != NULLPROC)
  681.         prev->next = next;
  682.     else {
  683.         switch (entry->state) {
  684.             case READY:
  685.                 Rdytab = next;
  686.                 break;
  687.             case WAITING:
  688.                 Waittab[phash (entry->event)] = next;
  689.                 break;
  690.             case SUSPEND:
  691.             case SUSPEND | WAITING:
  692.                 Susptab = next;
  693.                 break;
  694.             default:
  695.                 break;
  696.         }
  697.     }
  698.     entry->next = entry->prev = NULLPROC;
  699.  
  700.     switch (entry->state) {
  701.         case READY:
  702.             if (entry == Rdytail)
  703.                 Rdytail = prev;
  704.             break;
  705.         case WAITING:
  706.             if (entry == Waittail[phash (entry->event)])
  707.                 Waittail[phash (entry->event)] = prev;
  708.             break;
  709.         case SUSPEND:
  710.         case SUSPEND | WAITING:
  711.             if (entry == Susptail)
  712.                 Susptail = prev;
  713.             break;
  714.         default:
  715.             break;
  716.     }
  717.  
  718.     restore (i_state);
  719. }
  720.  
  721.  
  722.  
  723. /* Append proc entry to end of appropriate list */
  724. static void
  725. addproc (entry)
  726. register struct proc *entry;    /* Pointer to entry */
  727. {
  728. struct proc **head, **tail;
  729. int i_state;
  730.  
  731.     if (!valid_proc (entry))
  732.         return;
  733.  
  734.     switch (entry->state) {
  735.         case READY:
  736.             head = &Rdytab;
  737.             tail = &Rdytail;
  738.             break;
  739.         case WAITING:
  740.             head = &Waittab[phash (entry->event)];
  741.             tail = &Waittail[phash (entry->event)];
  742.             break;
  743.         case SUSPEND:
  744.         case SUSPEND | WAITING:
  745.             head = &Susptab;
  746.             tail = &Susptail;
  747.             break;
  748.         default:
  749.             head = 0;    /* silence warning */
  750.             tail = 0;
  751.             break;
  752.     }
  753.     if (head) {
  754.         entry->next = NULLPROC;
  755.         i_state = disable ();
  756.         if (!valid_proc (*head)) {
  757.             if (*head && shall_we_crash())
  758.                 crash_it_already ("corrupted process table");
  759.             /* Empty list, stick at beginning */
  760.             entry->prev = NULLPROC;
  761.             *head = entry;
  762.             if (tail)        /* should always be true */
  763.                 *tail = entry;
  764.         } else {
  765.             if (tail)    {    /* should always be true */
  766.                 if (!valid_proc(*tail))
  767.                     crash_it_already ("corrupted process table");
  768.                 (*tail)->next = entry;
  769.                 entry->prev = *tail;
  770.                 *tail = entry;
  771.             }
  772.         }
  773.         restore (i_state);
  774.     }
  775. }
  776.  
  777.  
  778. #ifdef MSDOS
  779. END_OF_FUNCTION(ksignal)
  780. #endif
  781.